﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;

namespace WaterTrans.GlyphLoader.Tests
{
    [TestClass]
    public class TypefaceExample
    {
        [TestMethod]
        public void CreateSingleAdjustmentGlyphOutline()
        {
            string fontPath = System.IO.Path.Combine(Environment.CurrentDirectory, "NotoSerifJP-Regular.otf");
            Typeface tf;
            using (var fontStream = System.IO.File.OpenRead(fontPath))
            {
                // Initialize stream only
                tf = new Typeface(fontStream);
            }

            // Get halt glyph adjustment (https://docs.microsoft.com/en-us/typography/opentype/spec/features_fj#halt)
            // The user may invoke this feature in a CJKV font to get better fit for punctuation or symbol glyphs without disrupting the monospaced alignment.
            var halt = tf.GetSingleAdjustmentMap("DFLT.DFLT.halt");

            var svg = new System.Text.StringBuilder();
            double unit = 100;
            double x = 20;
            double y = 20;
            string japaneseText = "【墨括弧】「鉤括弧」";

            svg.AppendLine("<svg width='840' height='140' viewBox='0 0 840 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>");

            foreach (char c in japaneseText)
            {
                // Get glyph index
                ushort glyphIndex = tf.CharacterToGlyphMap[(int)c];

                // Get glyph outline
                var geometry = tf.GetGlyphOutline(glyphIndex, unit);

                // Get advanced width
                double advanceWidth = tf.AdvanceWidths[glyphIndex] * unit;

                // Get advanced height
                double advanceHeight = tf.AdvanceHeights[glyphIndex] * unit;

                // Get baseline
                double baseline = tf.Baseline * unit;

                // Get halt adjustment
                double xPlacement = 0;
                if (halt.ContainsKey(glyphIndex))
                {
                    var adjustment = halt[glyphIndex];
                    xPlacement = adjustment.XPlacement * unit;
                    advanceWidth += adjustment.XAdvance * unit;
                }

                // Convert to path mini-language
                string miniLanguage = geometry.Figures.ToString(x + xPlacement, y + baseline);

                svg.AppendLine($"<path d='{miniLanguage}' fill='black' stroke='black' stroke-width='0' />");
                x += advanceWidth;
            }

            svg.AppendLine("</svg>");
            System.Diagnostics.Trace.WriteLine(svg.ToString());
            /* Result
            <svg width='840' height='140' viewBox='0 0 840 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>
            <path d='M66.3,114.6C50.5,107.5 40,92 40,70C40,48 50.5,32.5 66.3,25.4L66.3,23.7L32,23.7L32,116.3L66.3,116.3z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M95.1,50.9L95.1,43.3L116.7,43.3L116.7,50.9z M116.7,32.6L116.7,40.3L95.1,40.3L95.1,32.6z M144.6,32.6L144.6,40.3L123.2,40.3L123.2,32.6z M123.2,50.9L123.2,43.3L144.6,43.3L144.6,50.9z M75.5,71.8L76.4,74.8L162.2,74.8C163.6,74.8 164.7,74.3 164.9,73.2C161.6,70.2 156.4,66.2 156.4,66.2L151.7,71.8L123.2,71.8L123.2,64.2L154.7,64.2C156.2,64.2 157.1,63.7 157.3,62.6C154.2,59.8 149.4,56.2 149.4,56.2L145.1,61.3L123.2,61.3L123.2,53.8L144.6,53.8L144.6,56.4L145.6,56.4C147.8,56.4 151,54.8 151.1,54.1L151.1,33.8C153,33.4 154.7,32.6 155.4,31.8L147.3,25.7L143.6,29.6L96.3,29.6L88.7,26.4L88.7,57.9L89.7,57.9C92.9,57.9 95.1,56.2 95.1,55.7L95.1,53.8L116.7,53.8L116.7,61.3L83.8,61.3L84.7,64.2L116.7,64.2L116.7,71.8z M145.5,77.1C150.4,80.4 156.3,86.8 157.8,92C165.1,96.2 168.9,81 146.5,76.2z M125,77.1C127.9,80.2 131.1,85.7 131.4,90C137.3,94.9 143.3,82.5 126.1,76.4z M104.2,77.3C105.1,80.6 105.6,85.8 105,90C109.5,95.7 117.8,86.1 105.6,76.9z M87.5,76.7C87,81.8 82.5,85.8 78.5,87.1C76.5,88.2 75.1,89.9 75.8,91.9C76.7,94.1 80,94.2 82.5,92.9C86.3,91 90.9,85.8 89.3,76.8z M152,110.3L123.3,110.3L123.3,98.6L153.9,98.6C155.3,98.6 156.3,98.1 156.6,97C153.2,93.9 147.8,89.7 147.8,89.7L143,95.6L123.3,95.6L123.3,89.7C125.5,89.3 126.4,88.4 126.6,87.1L116.7,86.2L116.7,95.6L85,95.6L85.8,98.6L116.7,98.6L116.7,110.3L74.5,110.3L75.3,113.2L163.4,113.2C164.8,113.2 165.7,112.7 166,111.6C162.6,108.5 157,104.1 157,104.1z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M209.3,65.1C204.4,66.8 199.5,68.4 194.9,70L194.9,50L206.9,50C208.2,50 209.1,49.5 209.4,48.4C206.7,45.5 201.9,41.5 201.9,41.5L197.8,47L194.9,47L194.9,28C197.3,27.7 198.3,26.7 198.6,25.3L188.6,24.2L188.6,47L174.2,47L174.9,50L188.6,50L188.6,72C181.6,74.3 175.8,76 172.6,76.8L175.9,85.3C176.8,84.9 177.7,83.9 178,82.7C181.8,80.9 185.3,79.2 188.6,77.5L188.6,105.6C188.6,107.1 188.1,107.6 186.4,107.6C184.6,107.6 175.9,106.9 175.9,106.9L175.9,108.6C179.8,109.1 182,109.8 183.3,111C184.5,111.9 185,113.7 185.3,115.7C193.9,114.8 194.9,111.6 194.9,106.2L194.9,74.3C200.7,71.3 205.7,68.7 209.7,66.6z M252.7,80.9L252.7,105.8L219.4,105.8L219.4,80.9z M253.4,55L238.9,55L238.9,35.6C245.6,34.3 251.8,32.9 256.9,31.6C259.2,32.6 261,32.6 261.9,31.7L254.4,24.9C244.3,29.2 224.7,35.1 209,37.9L209.5,39.6C217,39 224.9,38 232.4,36.7L232.4,55L206.9,55L207.7,58L232.4,58L232.4,78L219.9,78L213.1,74.9L213.1,115.7L214.1,115.7C216.7,115.7 219.4,114.2 219.4,113.5L219.4,108.7L252.7,108.7L252.7,115L253.7,115C255.8,115 259,113.5 259.1,112.9L259.1,82.2C261.2,81.8 262.8,80.9 263.5,80.1L255.4,73.9L251.7,78L238.9,78L238.9,58L264.2,58C265.5,58 266.5,57.5 266.7,56.4C263.5,53.3 258,49 258,49z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M299.5,67.9L296,71.7L281.9,71.7C282.6,65.4 283.1,58.4 283.5,53.7L296.6,53.7L296.6,58.2L297.5,58.2C299.5,58.2 302.6,56.8 302.7,56.2L302.7,34C304.7,33.6 306.3,32.7 307,31.9L299.1,26L295.6,29.8L274.4,29.8L275.2,32.8L296.6,32.8L296.6,50.8L284.9,50.8L278.3,48.1C277.7,55.9 276.3,70.3 274.9,80.4C278.1,80.8 279.5,80.6 281.1,79.7C281.3,78.2 281.5,76.5 281.6,74.7L296.9,74.7C295.9,93.3 293.7,104.4 291,106.9C289.9,107.7 289.1,107.9 287.3,107.9C285.4,107.9 279.4,107.4 275.9,107.1L275.8,108.8C279,109.3 282.4,110.2 283.5,111.1C284.8,112 285.2,113.7 285.2,115.6C289,115.6 292.4,114.5 294.9,112.2C299.1,108.5 301.8,96.4 302.9,75.3C304.9,75.1 306.2,74.7 306.9,73.8z M354.6,24.9C346.8,28.3 332.4,32.6 319.8,35L312.8,32.5L312.8,56.2C312.8,75.3 311.4,96.6 300.1,114.5L301.8,115.7C317.5,98 318.8,73.5 318.8,56.3L318.8,37.2C322.7,36.9 326.8,36.6 330.8,36.1L330.8,101.1C323.9,102.4 318.1,103.4 314.7,103.7L318.8,111.6C319.7,111.4 320.6,110.6 321,109.4C332.1,105.5 340.7,102.4 347.1,100C348.4,104 349.3,108.1 349.3,111.6C355.5,117.8 361.5,102.1 342.4,85.4L341,85.9C342.9,89.3 344.9,93.7 346.5,98.2L336.7,100.1L336.7,35.3C341,34.7 345.2,34 349,33.2C349.5,66 350.7,96.3 362.6,115.6C363.9,112.2 366.1,110.3 368.3,109.7L368.6,108.8C355.8,93.5 352.2,59.4 351.2,32.8C353.2,32.4 355.2,32 356.9,31.6C359.1,32.5 360.9,32.5 361.8,31.7z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M373.7,114.6L373.7,116.3L408,116.3L408,23.7L373.7,23.7L373.7,25.4C389.5,32.5 400,48 400,70C400,92 389.5,107.5 373.7,114.6z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M435.7,88.7L439.4,88.7L439.4,27.2L466.3,27.2L466.3,23.7L435.7,23.7z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M497.3,71.2L512.6,71.2C514,71.2 514.9,70.7 515.2,69.7C512.3,66.7 507.5,62.7 507.5,62.7L503.2,68.3L497.3,68.3L497.3,55.5L509.2,55.5C510.6,55.5 511.5,55 511.7,54C508.9,51.2 504.2,47.3 504.2,47.3L500,52.7L481.9,52.7C487.8,45.9 492.9,38 496.3,31.1C502.1,36.3 506.6,42.3 508.5,46.6C514.3,50.7 521.5,38.8 497.1,29.4C499.6,29.4 500.6,28.8 500.9,27.7L491.3,24.3C488.3,34.9 480.1,51 471.8,60L473.2,61C476.2,58.7 479.1,55.9 481.7,52.9L482.5,55.5L491.2,55.5L491.2,68.3L475,68.3L475.8,71.2L491.2,71.2L491.2,103.1C483.8,104.7 477.7,106 474.1,106.6L478.7,114.9C479.7,114.5 480.5,113.7 480.9,112.5C496.4,107 507.7,102.4 515.8,99L515.4,97.6C509.2,99 503,100.5 497.3,101.7z M477.8,77C479.6,82.4 481.4,90.6 480.8,96.9C485.6,102.6 492.2,90.3 479.3,76.7z M502.7,96.3C505.5,92 508.2,85.9 510.3,80.6C512.3,80.6 513.4,79.7 513.8,78.6L504.6,75.8C503.7,82.6 502.3,90.4 500.9,95.6z M538.8,60.6L538.8,83.1L525.7,83.1L525.7,60.6z M538.8,86.1L538.8,92.7L539.7,92.7C541.5,92.7 544.5,91.3 544.6,90.6L544.6,61.8C546.5,61.4 548.1,60.6 548.8,59.8L541.1,54L537.8,57.7L526.1,57.7L520,54.8L520,94.8L521,94.8C523.4,94.8 525.7,93.4 525.7,92.8L525.7,86.1z M558.9,37.4L555.2,41.7L525.6,41.7C527.7,37.8 529.5,33.6 531.1,29.3C533.2,29.4 534.4,28.5 534.8,27.4L524.6,24.2C521.4,38.5 515.3,52.7 508.9,61.7L510.3,62.6C515.4,57.9 520,51.7 524.1,44.6L556.2,44.6C555.5,79.5 554.1,102.2 550.3,105.9C549.2,107.1 548.6,107.3 546.5,107.3C544.3,107.3 537.3,106.7 532.8,106.2L532.7,108.1C536.7,108.7 540.8,109.7 542.4,110.9C543.8,111.9 544.2,113.7 544.2,115.8C548.9,115.8 552.7,114.3 555.5,110.9C560,105.2 561.8,82.9 562.5,45.5C564.6,45.2 565.9,44.7 566.6,43.8z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M609.3,65.1C604.4,66.8 599.5,68.4 594.9,70L594.9,50L606.9,50C608.2,50 609.1,49.5 609.4,48.4C606.7,45.5 601.9,41.5 601.9,41.5L597.8,47L594.9,47L594.9,28C597.3,27.7 598.3,26.7 598.6,25.3L588.6,24.2L588.6,47L574.2,47L574.9,50L588.6,50L588.6,72C581.6,74.3 575.8,76 572.6,76.8L575.9,85.3C576.8,84.9 577.7,83.9 578,82.7C581.8,80.9 585.3,79.2 588.6,77.5L588.6,105.6C588.6,107.1 588.1,107.6 586.4,107.6C584.6,107.6 575.9,106.9 575.9,106.9L575.9,108.6C579.8,109.1 582,109.8 583.3,111C584.5,111.9 585,113.7 585.3,115.7C593.9,114.8 594.9,111.6 594.9,106.2L594.9,74.3C600.7,71.3 605.7,68.7 609.7,66.6z M652.7,80.9L652.7,105.8L619.4,105.8L619.4,80.9z M653.4,55L638.9,55L638.9,35.6C645.6,34.3 651.8,32.9 656.9,31.6C659.2,32.6 661,32.6 661.9,31.7L654.4,24.9C644.3,29.2 624.7,35.1 609,37.9L609.5,39.6C617,39 624.9,38 632.4,36.7L632.4,55L606.9,55L607.7,58L632.4,58L632.4,78L619.9,78L613.1,74.9L613.1,115.7L614.1,115.7C616.7,115.7 619.4,114.2 619.4,113.5L619.4,108.7L652.7,108.7L652.7,115L653.7,115C655.8,115 659,113.5 659.1,112.9L659.1,82.2C661.2,81.8 662.8,80.9 663.5,80.1L655.4,73.9L651.7,78L638.9,78L638.9,58L664.2,58C665.5,58 666.5,57.5 666.7,56.4C663.5,53.3 658,49 658,49z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M699.5,67.9L696,71.7L681.9,71.7C682.6,65.4 683.1,58.4 683.5,53.7L696.6,53.7L696.6,58.2L697.5,58.2C699.5,58.2 702.6,56.8 702.7,56.2L702.7,34C704.7,33.6 706.3,32.7 707,31.9L699.1,26L695.6,29.8L674.4,29.8L675.2,32.8L696.6,32.8L696.6,50.8L684.9,50.8L678.3,48.1C677.7,55.9 676.3,70.3 674.9,80.4C678.1,80.8 679.5,80.6 681.1,79.7C681.3,78.2 681.5,76.5 681.6,74.7L696.9,74.7C695.9,93.3 693.7,104.4 691,106.9C689.9,107.7 689.1,107.9 687.3,107.9C685.4,107.9 679.4,107.4 675.9,107.1L675.8,108.8C679,109.3 682.4,110.2 683.5,111.1C684.8,112 685.2,113.7 685.2,115.6C689,115.6 692.4,114.5 694.9,112.2C699.1,108.5 701.8,96.4 702.9,75.3C704.9,75.1 706.2,74.7 706.9,73.8z M754.6,24.9C746.8,28.3 732.4,32.6 719.8,35L712.8,32.5L712.8,56.2C712.8,75.3 711.4,96.6 700.1,114.5L701.8,115.7C717.5,98 718.8,73.5 718.8,56.3L718.8,37.2C722.7,36.9 726.8,36.6 730.8,36.1L730.8,101.1C723.9,102.4 718.1,103.4 714.7,103.7L718.8,111.6C719.7,111.4 720.6,110.6 721,109.4C732.1,105.5 740.7,102.4 747.1,100C748.4,104 749.3,108.1 749.3,111.6C755.5,117.8 761.5,102.1 742.4,85.4L741,85.9C742.9,89.3 744.9,93.7 746.5,98.2L736.7,100.1L736.7,35.3C741,34.7 745.2,34 749,33.2C749.5,66 750.7,96.3 762.6,115.6C763.9,112.2 766.1,110.3 768.3,109.7L768.6,108.8C755.8,93.5 752.2,59.4 751.2,32.8C753.2,32.4 755.2,32 756.9,31.6C759.1,32.5 760.9,32.5 761.8,31.7z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M804.3,51.3L800.6,51.3L800.6,112.8L773.7,112.8L773.7,116.3L804.3,116.3z ' fill='black' stroke='black' stroke-width='0' />
            </svg>
            */
        }

        [TestMethod]
        public void CreatePairAdjustmentGlyphOutline()
        {
            string fontPath = System.IO.Path.Combine(Environment.CurrentDirectory, "Lora-VariableFont_wght.ttf");
            Typeface tf;
            using (var fontStream = System.IO.File.OpenRead(fontPath))
            {
                // Initialize stream only
                tf = new Typeface(fontStream);
            }

            // Get kern glyph adjustment (https://docs.microsoft.com/en-us/typography/opentype/spec/features_ko#tag-kern)
            var kern = tf.GetPairAdjustmentMap("DFLT.DFLT.kern");

            var glyphList = new List<ushort>();

            string kerningText = "You Won.";

            foreach (char c in kerningText)
            {
                // Get glyph index
                ushort glyphIndex = tf.CharacterToGlyphMap[(int)c];
                glyphList.Add(glyphIndex);
            }

            var svg = new System.Text.StringBuilder();
            double unit = 100;
            double x = 20;
            double y = 20;


            svg.AppendLine("<svg width='540' height='140' viewBox='0 0 540 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>");

            bool secondKern = false;
            double secondXPlacement = 0;
            double secondXAdvance = 0;

            for (int i = 0; i < glyphList.Count; i++)
            {
                ushort glyphIndex = glyphList[i];

                // Get glyph outline
                var geometry = tf.GetGlyphOutline(glyphIndex, unit);

                // Get advanced width
                double advanceWidth = tf.AdvanceWidths[glyphIndex] * unit;

                // Get advanced height
                double advanceHeight = tf.AdvanceHeights[glyphIndex] * unit;

                // Get baseline
                double baseline = tf.Baseline * unit;

                // Get kern adjustment
                ushort[] key;
                if (i < glyphList.Count - 1)
                {
                    key = new ushort[] { glyphList[i], glyphList[i + 1] };
                }
                else
                {
                    key = new ushort[] { glyphList[i] };
                }

                double xPlacement = 0;
                if (secondKern)
                {
                    xPlacement = secondXPlacement;
                    advanceWidth += secondXAdvance;
                    secondKern = false;
                }

                if (kern.ContainsKey(key))
                {
                    var adjustment = kern[key];
                    xPlacement += adjustment.First.XPlacement * unit;
                    advanceWidth += adjustment.First.XAdvance * unit;
                    secondXPlacement = adjustment.Second.XPlacement * unit;
                    secondXAdvance = adjustment.Second.XAdvance * unit;
                    secondKern = true;
                }

                // Convert to path mini-language
                string miniLanguage = geometry.Figures.ToString(x + xPlacement, y + baseline);

                svg.AppendLine($"<path d='{miniLanguage}' fill='black' stroke='black' stroke-width='0' />");
                x += advanceWidth;
            }

            svg.AppendLine("</svg>");
            System.Diagnostics.Trace.WriteLine(svg.ToString());
            /* Result
            <svg width='540' height='140' viewBox='0 0 540 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>
            <path d='M65,120.6L41.5,120.6L41.5,117.3Q45.3,117.1 46.65,115.5Q48,113.9 48.15,111.15Q48.3,108.4 48.3,105L48.3,105L48.4,93.6L31,66.1Q28.5,62.1 27.25,59.4Q26,56.7 25.6,54.8L25.6,54.8Q24,54.9 22.5,54.9Q21,54.9 19.4,55L19.4,55L19.4,50.6L45.2,50.6L45.2,53.9Q40.6,53.9 38.8,55.3Q37,56.7 37.45,59.15Q37.9,61.6 39.9,64.8L39.9,64.8L47.9,77.4Q48.8,78.8 49.8,80.3Q50.8,81.8 51.85,83.35Q52.9,84.9 54.1,86.6L54.1,86.6L54.3,86.6Q55.4,84.4 56.5,82.35Q57.6,80.3 58.6,78.4L58.6,78.4L67.1,62.3Q67.6,61.3 68.35,59.95Q69.1,58.6 70,57.15Q70.9,55.7 71.9,54.7L71.9,54.7Q70,54.8 68,54.85Q66,54.9 64,55L64,55L64,50.6L84.4,50.6L84.4,53.9Q79.5,54.2 76.35,57.3Q73.2,60.4 69.7,66.8L69.7,66.8Q66.3,73.2 63.15,79.1Q60,85 57.1,90.6L57.1,90.6Q57.1,92.4 57.05,95.4Q57,98.4 57,101.45Q57,104.5 57,106.6Q57,108.7 57,108.7L57,108.7Q57,111.4 56.95,113.35Q56.9,115.3 56.7,116.6L56.7,116.6Q58.8,116.5 60.85,116.4Q62.9,116.3 65,116.2L65,116.2L65,120.6z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M105.6,122.2L105.6,122.2Q98.6,122.2 92.9,118.95Q87.2,115.7 83.85,109.95Q80.5,104.2 80.5,96.8L80.5,96.8Q80.5,88.9 83.8,82.6Q87.1,76.3 92.8,72.65Q98.5,69 105.6,69L105.6,69Q112.6,69 118.3,72.35Q124,75.7 127.4,81.4Q130.8,87.1 130.8,94.4L130.8,94.4Q130.8,102.1 127.45,108.45Q124.1,114.8 118.4,118.5Q112.7,122.2 105.6,122.2z M106.4,118.2L106.4,118.2Q111.7,118.2 114.8,115.2Q117.9,112.2 119.25,107.4Q120.6,102.6 120.6,97.3L120.6,97.3Q120.6,92.8 119.75,88.45Q118.9,84.1 117.1,80.55Q115.3,77 112.45,74.9Q109.6,72.8 105.6,72.8L105.6,72.8Q100.4,72.8 97.1,75.8Q93.8,78.8 92.25,83.6Q90.7,88.4 90.7,93.9L90.7,93.9Q90.7,100.1 92.4,105.65Q94.1,111.2 97.6,114.7Q101.1,118.2 106.4,118.2z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M160.4,122.2L160.4,122.2Q155,122.2 151.35,120.2Q147.7,118.2 145.85,113.4Q144,108.6 144,100.4L144,100.4L144,82.6Q144,81 144.05,79.4Q144.1,77.8 144.4,76.1L144.4,76.1Q142.7,76.2 140.95,76.25Q139.2,76.3 137.5,76.4L137.5,76.4L137.5,72.3L140.6,72.3Q144.9,72.3 146.85,71.45Q148.8,70.6 149.9,69.6L149.9,69.6L152.8,69.6L152.8,100.1Q152.8,108.7 155.25,112.95Q157.7,117.2 163.6,117.1L163.6,117.1Q167.4,117 170.85,114.75Q174.3,112.5 176.4,109.4L176.4,109.4L176.4,83.7Q176.4,81.3 176.5,79.55Q176.6,77.8 176.9,76.1L176.9,76.1Q175.1,76.2 173.3,76.25Q171.5,76.3 169.7,76.4L169.7,76.4L169.7,72.3L172.8,72.3Q177.1,72.3 179.05,71.45Q181,70.6 182.1,69.6L182.1,69.6L185,69.6L184.9,107.4Q184.9,109 184.8,111.9Q184.7,114.8 184.5,116.8L184.5,116.8Q186.3,116.7 188.1,116.6Q189.9,116.5 191.7,116.4L191.7,116.4L191.7,120.6L177.4,120.6Q177.1,118.9 176.95,117.4Q176.8,115.9 176.7,114.6L176.7,114.6Q173.6,117.7 169.2,119.95Q164.8,122.2 160.4,122.2z ' fill='black' stroke='black' stroke-width='0' />
            <path d='' fill='black' stroke='black' stroke-width='0' />
            <path d='M252.2,121.6L249.3,121.6L231.4,68.4Q229.7,63.1 228.7,60.05Q227.7,57 227.2,54.8L227.2,54.8Q225.8,54.9 224.4,54.9Q223,54.9 221.6,55L221.6,55L221.6,50.6L245.9,50.6L245.9,53.9Q240.1,54.2 238.95,56.5Q237.8,58.8 239.4,64.8L239.4,64.8Q241.1,71.4 243.1,76.7Q245.1,82 247,88.1L247,88.1Q248.4,92.6 249.85,96.4Q251.3,100.2 252.8,104.9L252.8,104.9L253,104.9Q253.5,103.2 254.05,101.3Q254.6,99.4 255.2,97.6Q255.8,95.8 256.3,94.25Q256.8,92.7 257.1,91.7L257.1,91.7Q259.9,82.8 262.65,74.45Q265.4,66.1 267.5,59.75Q269.6,53.4 270.4,50.4L270.4,50.4L273.6,50.4Q274.5,53.7 276.2,58.8Q277.9,63.9 279.8,69.5Q281.7,75.1 283.35,80.1Q285,85.1 286,88.1L286,88.1Q287.4,92.6 288.95,97Q290.5,101.4 291.8,106.1L291.8,106.1L292.1,106.1Q293,103.2 294.05,99.9Q295.1,96.6 296.2,93.2L296.2,93.2Q298.8,85.8 300.45,80.8Q302.1,75.8 303.15,72.5Q304.2,69.2 304.95,66.75Q305.7,64.3 306.5,62L306.5,62Q307.1,60.3 307.85,58.35Q308.6,56.4 309.6,54.7L309.6,54.7Q307.6,54.8 305.6,54.85Q303.6,54.9 301.6,55L301.6,55L301.6,50.6L321.9,50.6L321.9,53.9Q318.5,54.3 316.55,55.4Q314.6,56.5 313.1,59.5Q311.6,62.5 309.5,68.7L309.5,68.7Q304.9,82.3 300.55,95.45Q296.2,108.6 291.5,121.6L291.5,121.6L288.5,121.6L273.3,78.2Q272.4,75.6 271.55,73.1Q270.7,70.6 269.8,68.1L269.8,68.1Q269,70.6 268.15,73.1Q267.3,75.6 266.5,78.1L266.5,78.1L252.2,121.6z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M345.7,122.2L345.7,122.2Q338.7,122.2 333,118.95Q327.3,115.7 323.95,109.95Q320.6,104.2 320.6,96.8L320.6,96.8Q320.6,88.9 323.9,82.6Q327.2,76.3 332.9,72.65Q338.6,69 345.7,69L345.7,69Q352.7,69 358.4,72.35Q364.1,75.7 367.5,81.4Q370.9,87.1 370.9,94.4L370.9,94.4Q370.9,102.1 367.55,108.45Q364.2,114.8 358.5,118.5Q352.8,122.2 345.7,122.2z M346.5,118.2L346.5,118.2Q351.8,118.2 354.9,115.2Q358,112.2 359.35,107.4Q360.7,102.6 360.7,97.3L360.7,97.3Q360.7,92.8 359.85,88.45Q359,84.1 357.2,80.55Q355.4,77 352.55,74.9Q349.7,72.8 345.7,72.8L345.7,72.8Q340.5,72.8 337.2,75.8Q333.9,78.8 332.35,83.6Q330.8,88.4 330.8,93.9L330.8,93.9Q330.8,100.1 332.5,105.65Q334.2,111.2 337.7,114.7Q341.2,118.2 346.5,118.2z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M399.8,120.6L379.4,120.6L379.4,117.6Q382.5,117.6 383.7,116.05Q384.9,114.5 385.1,111.75Q385.3,109 385.3,105.4L385.3,105.4L385.4,82.6Q385.4,81 385.45,79.4Q385.5,77.8 385.8,76.1L385.8,76.1Q384,76.2 382.25,76.3Q380.5,76.4 378.7,76.5L378.7,76.5L378.7,72.3Q383.1,72.3 385.35,71.9Q387.6,71.5 388.7,70.9Q389.8,70.3 390.5,69.6L390.5,69.6L393.4,69.6Q393.5,70.3 393.55,71.2Q393.6,72.1 393.7,73.2Q393.8,74.3 393.8,75.7L393.8,75.7Q396,73.8 398.65,72.3Q401.3,70.8 404.25,69.9Q407.2,69 410.1,69L410.1,69Q418.8,69 422.8,74.45Q426.8,79.9 426.8,91.4L426.8,91.4L426.8,110Q426.8,112 426.75,113.55Q426.7,115.1 426.4,116.8L426.4,116.8Q428,116.7 429.55,116.65Q431.1,116.6 432.7,116.5L432.7,116.5L432.7,120.6L412.3,120.6L412.3,117.6Q415.4,117.6 416.6,116.05Q417.8,114.5 418,111.75Q418.2,109 418.2,105.4L418.2,105.4L418.2,91.4Q418.1,82.8 415.35,78.4Q412.6,74 406.7,74.1L406.7,74.1Q403.1,74.2 399.65,76Q396.2,77.8 393.9,80.6L393.9,80.6Q394,81.4 394,82.4Q394,83.4 394,84.5L394,84.5L393.9,110Q393.9,112 393.85,113.55Q393.8,115.1 393.5,116.8L393.5,116.8Q395.1,116.7 396.65,116.65Q398.2,116.6 399.8,116.5L399.8,116.5L399.8,120.6z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M447.9,122.2L447.9,122.2Q445.6,122.2 443.85,120.35Q442.1,118.5 442.1,115.8L442.1,115.8Q442.1,113.1 443.9,111.2Q445.7,109.3 448,109.3L448,109.3Q450.5,109.3 452.15,111.2Q453.8,113.1 453.8,115.8L453.8,115.8Q453.8,118.5 452,120.35Q450.2,122.2 447.9,122.2z ' fill='black' stroke='black' stroke-width='0' />
            </svg>
            */
        }


        [TestMethod]
        public void CreateAlternateGlyphOutline()
        {
            string fontPath = System.IO.Path.Combine(Environment.CurrentDirectory, "NotoSerifJP-Regular.otf");
            Typeface tf;
            using (var fontStream = System.IO.File.OpenRead(fontPath))
            {
                // Initialize stream only
                tf = new Typeface(fontStream);
            }

            // Get alternate glyph map
            var aaltMap = tf.GetAlternateSubstitutionMap("DFLT", "DFLT", "aalt");

            var svg = new System.Text.StringBuilder();
            double unit = 100;
            double x = 20;
            double y = 20;
            string japaneseText = "籾籾籾";

            var alternateIndex = -1;
            var glyphList = new List<ushort>();
            foreach (char c in japaneseText)
            {
                // Get glyph index
                ushort glyphIndex = tf.CharacterToGlyphMap[(int)c];

                if (aaltMap.ContainsKey(glyphIndex) && alternateIndex >= 0)
                {
                    // Convert to alternate
                    glyphList.Add(aaltMap[glyphIndex][alternateIndex]);
                }
                else
                {
                    glyphList.Add(glyphIndex);
                }
                alternateIndex += 1;
            }

            svg.AppendLine("<svg width='340' height='140' viewBox='0 0 340 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>");

            foreach (var glyphIndex in glyphList)
            {
                // Get glyph outline
                var geometry = tf.GetGlyphOutline(glyphIndex, unit);

                // Get advanced width
                double advanceWidth = tf.AdvanceWidths[glyphIndex] * unit;

                // Get advanced height
                double advanceHeight = tf.AdvanceHeights[glyphIndex] * unit;

                // Get baseline
                double baseline = tf.Baseline * unit;

                // Convert to path mini-language
                string miniLanguage = geometry.Figures.ToString(x, y + baseline);

                svg.AppendLine($"<path d='{miniLanguage}' fill='black' stroke='black' stroke-width='0' />");
                x += advanceWidth;
            }

            svg.AppendLine("</svg>");
            System.Diagnostics.Trace.WriteLine(svg.ToString());
            /* Result
            <svg width='340' height='140' viewBox='0 0 340 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>
            <path d='M25.8,32.6C27.8,38.1 30.3,46.4 30.2,52.8C35.5,58.4 41.8,45.9 27.2,32.1z M47.2,62.6L62,62.6C63.4,62.6 64.3,62.2 64.6,61.1C61.5,58.1 56.5,54.2 56.5,54.2L52.2,59.8L47.2,59.8L47.2,28.1C49.7,27.8 50.4,26.7 50.7,25.3L40.9,24.2L40.9,59.8L24.2,59.8L24.9,62.6L38.6,62.6C35.5,75.8 30.2,89.6 23,100.1L24.4,101.4C31.2,94.4 36.7,86.1 40.9,77.1L40.9,115.9L42.1,115.9C44.5,115.9 47.2,114.4 47.2,113.4L47.2,71.2C50.9,75.3 55,81 56.1,85.7C62.5,90.5 67.6,77.2 47.2,68.9z M51,54.8C55,49.8 58.9,42.5 62.2,35.9C64.3,36 65.4,35.1 65.8,33.9L56.2,30.7C54.4,38.9 51.7,48.1 49.4,54z M105,35.4C104.5,57.8 103.6,74.7 102.3,86.4C95.2,82.2 88.8,77 83.4,70.7C86.1,58.8 86.7,46.7 87,35.4z M107.9,27.9L104,32.4L65.4,32.4L66.2,35.4L80.4,35.4C80.2,44.4 80,54.3 78.4,64.3C74.2,58.1 70.9,51.1 68.7,43.3L66.7,44.4C69.1,53.9 72.8,62.4 77.5,69.8C74.4,85.2 67.9,100.7 54.1,114.3L55.7,115.9C70.2,104.2 77.8,90.4 81.9,76.2C87.4,83.3 93.9,89.2 101.3,93.8C100.2,100.2 98.9,104.1 97.4,105.6C96.1,106.8 95.3,107.1 93.3,107.1C91.2,107.1 86,106.7 82.5,106.3L82.4,108C85.8,108.7 88.8,109.7 90,110.8C91.1,111.8 91.4,113.7 91.4,115.9C95.6,115.9 99.7,114.4 102.7,110.7C104.5,108.4 106,104.1 107.3,97.3C109.5,98.4 111.7,99.4 114,100.3C114.6,97.5 115.8,95.4 118.3,94.7L118.5,93.6C115.1,92.5 111.7,91.2 108.4,89.6C109.9,77.6 110.9,60.2 111.5,36.3C113.7,36.1 115,35.5 115.7,34.6z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M125.8,32.6C127.8,38.1 130.3,46.4 130.2,52.8C135.5,58.4 141.8,45.9 127.2,32.1z M147.2,62.6L162,62.6C163.4,62.6 164.3,62.2 164.6,61.1C161.5,58.1 156.5,54.2 156.5,54.2L152.2,59.8L147.2,59.8L147.2,28.1C149.7,27.8 150.4,26.7 150.7,25.3L140.9,24.2L140.9,59.8L124.2,59.8L124.9,62.6L138.6,62.6C135.5,75.8 130.2,89.6 123,100.1L124.4,101.4C131.2,94.4 136.7,86.1 140.9,77.1L140.9,115.9L142.1,115.9C144.5,115.9 147.2,114.4 147.2,113.4L147.2,71.2C150.9,75.3 155,81 156.1,85.7C162.5,90.5 167.6,77.2 147.2,68.9z M151,54.8C155,49.8 158.9,42.5 162.2,35.9C164.3,36 165.4,35.1 165.8,33.9L156.2,30.7C154.4,38.9 151.7,48.1 149.4,54z M205.1,35.4C204.5,58 203.6,75.1 202.2,86.8C195.1,82.2 188.8,76.4 183.8,69.4C186.3,57.9 186.9,46.3 187.2,35.4z M208,27.9L204,32.4L165.4,32.4L166.2,35.4L180.6,35.4C180.4,43.6 180.2,52.5 179,61.6C176.6,57.2 174.7,52.3 173.3,47.1L176.1,42.4L172.3,41.5L171.3,46.8C168.9,49.8 165.1,53.8 162.8,55.8L167.9,60.4C168.4,59.8 168.6,59 168,58.2C169.1,56.2 170.5,53.2 171.8,50.4C173.4,56.5 175.5,62.1 178.1,67.3C175.2,83.5 168.7,100 153.9,114.3L155.5,115.9C170.6,103.8 178.3,89.5 182.4,74.8C187.5,82.7 193.8,89.2 201.1,94.2C200,100.3 198.7,104.1 197.2,105.6C195.9,106.8 195.1,107.1 193.1,107.1C191,107.1 185.7,106.7 182.3,106.3L182.2,108C185.4,108.7 188.5,109.7 189.7,110.8C190.8,111.8 191.1,113.7 191.1,115.9C195.4,115.9 199.4,114.4 202.4,110.7C204.2,108.5 205.7,104.4 207,97.9C209.2,99.2 211.6,100.3 214,101.3C214.6,98.4 215.8,96.4 218.2,95.6L218.4,94.5C214.9,93.3 211.5,91.9 208.2,90.2C209.8,78.1 210.9,60.6 211.5,36.3C213.8,36.1 215,35.5 215.8,34.6z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M225.8,32.6C227.8,38.1 230.3,46.4 230.2,52.8C235.5,58.4 241.8,45.9 227.2,32.1z M247.2,62.6L262,62.6C263.4,62.6 264.3,62.2 264.6,61.1C261.5,58.1 256.5,54.2 256.5,54.2L252.2,59.8L247.2,59.8L247.2,28.1C249.7,27.8 250.4,26.7 250.7,25.3L240.9,24.2L240.9,59.8L224.2,59.8L224.9,62.6L238.6,62.6C235.5,75.8 230.2,89.6 223,100.1L224.4,101.4C231.2,94.4 236.7,86.1 240.9,77.1L240.9,115.9L242.1,115.9C244.5,115.9 247.2,114.4 247.2,113.4L247.2,71.2C250.9,75.3 255,81 256.1,85.7C262.5,90.5 267.6,77.2 247.2,68.9z M308.2,28L304.3,32.5L265.2,32.5L265.6,33.8L256.2,30.7C254.4,38.9 251.7,48.1 249.4,54L251,54.8C255,49.8 258.9,42.5 262.2,35.9C264.1,36 265.2,35.3 265.7,34.2L266,35.5L279.9,35.5C279.8,44.7 279.6,54.4 278.3,64.1C274.5,61.2 269.8,58.2 264.3,55.2L263.1,56.2C267.5,60 272.7,65 277.3,70.4C274.4,85.8 268,101.1 254.2,114.3L255.9,116C270.6,104.4 278.1,90.7 282.1,76.3C285.3,80.5 287.9,84.6 289.3,88.2C295.5,92.4 298.7,82.5 283.9,68.8C286,57.7 286.4,46.4 286.7,35.5L305.4,35.5C304.8,77.1 303.6,101.6 299.8,105.6C298.8,106.7 298.1,107 296,107C293.8,107 287.7,106.5 283.6,106L283.5,107.8C287.3,108.6 291,109.6 292.4,110.7C293.7,111.7 294,113.6 294,115.8C298.6,115.8 302.6,114.3 305.3,110.6C309.8,104.4 311.3,81.1 311.8,36.4C314,36.2 315.3,35.5 316,34.7z ' fill='black' stroke='black' stroke-width='0' />
            </svg>
            */
        }

        [TestMethod]
        public void CreateLigatureGlyphOutline()
        {
            string fontPath = System.IO.Path.Combine(Environment.CurrentDirectory, "Roboto-Regular.ttf");
            Typeface tf;
            using (var fontStream = System.IO.File.OpenRead(fontPath))
            {
                // Initialize stream only
                tf = new Typeface(fontStream);
            }

            var svg = new System.Text.StringBuilder();
            double unit = 100;
            double x = 20;
            double y = 20;
            string ligatureText = "fluent office";

            svg.AppendLine("<svg width='690' height='140' viewBox='0 0 690 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>");

            var glyphList = new List<ushort>();

            foreach (char c in ligatureText)
            {
                // Get glyph index
                ushort glyphIndex = tf.CharacterToGlyphMap[(int)c];

                // Get glyph outline
                var geometry = tf.GetGlyphOutline(glyphIndex, unit);

                // Get advanced width
                double advanceWidth = tf.AdvanceWidths[glyphIndex] * unit;

                // Get advanced height
                double advanceHeight = tf.AdvanceHeights[glyphIndex] * unit;

                // Get baseline
                double baseline = tf.Baseline * unit;

                // Convert to path mini-language
                string miniLanguage = geometry.Figures.ToString(x, y + baseline);

                svg.AppendLine($"<path d='{miniLanguage}' fill='black' stroke='black' stroke-width='0' />");
                x += advanceWidth;

                glyphList.Add(glyphIndex);
            }

            svg.AppendLine("</svg>");
            System.Diagnostics.Trace.WriteLine(svg.ToString());
            /* Result
            <svg width='690' height='140' viewBox='0 0 690 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>
            <path d='M40.31,95L31.28,95L31.28,49.15L22.93,49.15L22.93,42.17L31.28,42.17L31.28,36.75Q31.28,28.25 35.82,23.61Q40.36,18.97 48.66,18.97L48.66,18.97Q51.79,18.97 54.86,19.8L54.86,19.8L54.38,27.13Q52.08,26.69 49.49,26.69L49.49,26.69Q45.1,26.69 42.71,29.25Q40.31,31.82 40.31,36.6L40.31,36.6L40.31,42.17L51.59,42.17L51.59,49.15L40.31,49.15L40.31,95z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M71.37,20L71.37,95L62.33,95L62.33,20L71.37,20z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M118.63,95L118.44,89.78Q113.16,95.98 102.96,95.98L102.96,95.98Q94.51,95.98 90.09,91.07Q85.67,86.16 85.62,76.54L85.62,76.54L85.62,42.17L94.66,42.17L94.66,76.3Q94.66,88.31 104.42,88.31L104.42,88.31Q114.78,88.31 118.19,80.6L118.19,80.6L118.19,42.17L127.23,42.17L127.23,95L118.63,95z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M162.87,95.98L162.87,95.98Q152.13,95.98 145.39,88.92Q138.65,81.87 138.65,70.05L138.65,70.05L138.65,68.39Q138.65,60.53 141.66,54.35Q144.66,48.17 150.05,44.68Q155.45,41.19 161.75,41.19L161.75,41.19Q172.05,41.19 177.76,47.98Q183.48,54.77 183.48,67.41L183.48,67.41L183.48,71.17L147.69,71.17Q147.88,78.98 152.25,83.79Q156.62,88.6 163.36,88.6L163.36,88.6Q168.14,88.6 171.46,86.65Q174.79,84.7 177.28,81.47L177.28,81.47L182.79,85.77Q176.15,95.98 162.87,95.98z M161.75,48.61L161.75,48.61Q156.28,48.61 152.57,52.59Q148.86,56.57 147.98,63.75L147.98,63.75L174.44,63.75L174.44,63.07Q174.05,56.18 170.73,52.4Q167.41,48.61 161.75,48.61z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M193.93,42.17L202.47,42.17L202.76,48.81Q208.82,41.19 218.58,41.19L218.58,41.19Q235.33,41.19 235.48,60.09L235.48,60.09L235.48,95L226.45,95L226.45,60.04Q226.4,54.33 223.83,51.59Q221.27,48.86 215.85,48.86L215.85,48.86Q211.46,48.86 208.13,51.2Q204.81,53.54 202.96,57.35L202.96,57.35L202.96,95L193.93,95L193.93,42.17z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M252.32,29.38L261.36,29.38L261.36,42.17L271.22,42.17L271.22,49.15L261.36,49.15L261.36,81.91Q261.36,85.09 262.68,86.67Q263.99,88.26 267.17,88.26L267.17,88.26Q268.73,88.26 271.46,87.68L271.46,87.68L271.46,95Q267.9,95.98 264.53,95.98L264.53,95.98Q258.48,95.98 255.4,92.31Q252.32,88.65 252.32,81.91L252.32,81.91L252.32,49.15L242.71,49.15L242.71,42.17L252.32,42.17L252.32,29.38z ' fill='black' stroke='black' stroke-width='0' />
            <path d='' fill='black' stroke='black' stroke-width='0' />
            <path d='M304.13,68.73L304.13,68.1Q304.13,60.33 307.18,54.13Q310.23,47.93 315.68,44.56Q321.12,41.19 328.11,41.19L328.11,41.19Q338.9,41.19 345.56,48.66Q352.23,56.13 352.23,68.54L352.23,68.54L352.23,69.17Q352.23,76.88 349.27,83.01Q346.32,89.14 340.83,92.56Q335.33,95.98 328.2,95.98L328.2,95.98Q317.46,95.98 310.8,88.51Q304.13,81.04 304.13,68.73L304.13,68.73z M313.21,69.17L313.21,69.17Q313.21,77.96 317.29,83.28Q321.37,88.6 328.2,88.6L328.2,88.6Q335.09,88.6 339.14,83.21Q343.19,77.81 343.19,68.1L343.19,68.1Q343.19,59.4 339.07,54.01Q334.94,48.61 328.11,48.61L328.11,48.61Q321.42,48.61 317.31,53.94Q313.21,59.26 313.21,69.17z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M377.03,95L368,95L368,49.15L359.65,49.15L359.65,42.17L368,42.17L368,36.75Q368,28.25 372.54,23.61Q377.08,18.97 385.38,18.97L385.38,18.97Q388.51,18.97 391.58,19.8L391.58,19.8L391.09,27.13Q388.8,26.69 386.21,26.69L386.21,26.69Q381.82,26.69 379.42,29.25Q377.03,31.82 377.03,36.6L377.03,36.6L377.03,42.17L388.31,42.17L388.31,49.15L377.03,49.15L377.03,95z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M411.75,95L402.71,95L402.71,49.15L394.37,49.15L394.37,42.17L402.71,42.17L402.71,36.75Q402.71,28.25 407.26,23.61Q411.8,18.97 420.1,18.97L420.1,18.97Q423.22,18.97 426.3,19.8L426.3,19.8L425.81,27.13Q423.52,26.69 420.93,26.69L420.93,26.69Q416.53,26.69 414.14,29.25Q411.75,31.82 411.75,36.6L411.75,36.6L411.75,42.17L423.03,42.17L423.03,49.15L411.75,49.15L411.75,95z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M442.8,42.17L442.8,95L433.77,95L433.77,42.17L442.8,42.17z M433.04,28.15L433.04,28.15Q433.04,25.96 434.38,24.44Q435.72,22.93 438.36,22.93Q441,22.93 442.36,24.44Q443.73,25.96 443.73,28.15Q443.73,30.35 442.36,31.82Q441,33.28 438.36,33.28Q435.72,33.28 434.38,31.82Q433.04,30.35 433.04,28.15z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M478.45,88.6L478.45,88.6Q483.28,88.6 486.89,85.67Q490.51,82.74 490.9,78.35L490.9,78.35L499.44,78.35Q499.2,82.89 496.32,86.99Q493.44,91.09 488.63,93.54Q483.82,95.98 478.45,95.98L478.45,95.98Q467.66,95.98 461.28,88.77Q454.91,81.57 454.91,69.07L454.91,69.07L454.91,67.56Q454.91,59.84 457.74,53.84Q460.58,47.83 465.87,44.51Q471.17,41.19 478.4,41.19L478.4,41.19Q487.29,41.19 493.17,46.51Q499.05,51.84 499.44,60.33L499.44,60.33L490.9,60.33Q490.51,55.21 487.02,51.91Q483.53,48.61 478.4,48.61L478.4,48.61Q471.51,48.61 467.73,53.57Q463.95,58.53 463.95,67.9L463.95,67.9L463.95,69.61Q463.95,78.74 467.71,83.67Q471.46,88.6 478.45,88.6z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M531.52,95.98L531.52,95.98Q520.78,95.98 514.04,88.92Q507.3,81.87 507.3,70.05L507.3,70.05L507.3,68.39Q507.3,60.53 510.31,54.35Q513.31,48.17 518.71,44.68Q524.1,41.19 530.4,41.19L530.4,41.19Q540.7,41.19 546.42,47.98Q552.13,54.77 552.13,67.41L552.13,67.41L552.13,71.17L516.34,71.17Q516.53,78.98 520.9,83.79Q525.27,88.6 532.01,88.6L532.01,88.6Q536.8,88.6 540.12,86.65Q543.44,84.7 545.93,81.47L545.93,81.47L551.45,85.77Q544.8,95.98 531.52,95.98z M530.4,48.61L530.4,48.61Q524.93,48.61 521.22,52.59Q517.51,56.57 516.63,63.75L516.63,63.75L543.1,63.75L543.1,63.07Q542.71,56.18 539.38,52.4Q536.06,48.61 530.4,48.61z ' fill='black' stroke='black' stroke-width='0' />
            </svg>
            */

            x = 20;
            y = 20;
            svg.Clear();

            // Get ligature glyph map
            var ligaMap = tf.GetLigatureSubstitutionMap("latn", "DFLT", "liga");

            // Create ligature first glyph and glyph count dictionary
            var firstGlyphDic = new Dictionary<ushort, int>();
            foreach (var key in ligaMap.Keys)
            {
                if (!firstGlyphDic.ContainsKey(key[0]) || firstGlyphDic[key[0]] < key.Length)
                {
                    firstGlyphDic[key[0]] = key.Length;
                }
            }

            var ligatureGlyphList = new List<ushort>();

            for (int i = 0; i < glyphList.Count; i++)
            {
                bool found = false;

                // Glyph has ligature
                if (firstGlyphDic.ContainsKey(glyphList[i]))
                {
                    // Get maximum length of ligature
                    var ligatureMaxLength = firstGlyphDic[glyphList[i]];

                    // Determines whether ligature is possible from the maximum length.
                    for (int j = ligatureMaxLength; j > 0; j--)
                    {
                        if (glyphList.Count >= i + j)
                        { 
                            ushort[] key = glyphList.GetRange(i, j).ToArray();
                            if (ligaMap.ContainsKey(key))
                            {
                                ligatureGlyphList.Add(ligaMap[key]);
                                i += j - 1;
                                found = true;
                                break;
                            }
                        }
                    }
                }

                if (!found)
                {
                    ligatureGlyphList.Add(glyphList[i]);
                }
            }

            svg.AppendLine("<svg width='690' height='140' viewBox='0 0 690 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>");

            foreach (var glyphIndex in ligatureGlyphList)
            {
                // Get glyph outline
                var geometry = tf.GetGlyphOutline(glyphIndex, unit);

                // Get advanced width
                double advanceWidth = tf.AdvanceWidths[glyphIndex] * unit;

                // Get advanced height
                double advanceHeight = tf.AdvanceHeights[glyphIndex] * unit;

                // Get baseline
                double baseline = tf.Baseline * unit;

                // Convert to path mini-language
                string miniLanguage = geometry.Figures.ToString(x, y + baseline);

                svg.AppendLine($"<path d='{miniLanguage}' fill='black' stroke='black' stroke-width='0' />");
                x += advanceWidth;
            }

            svg.AppendLine("</svg>");
            System.Diagnostics.Trace.WriteLine(svg.ToString());
            /* Result
            <svg width='690' height='140' viewBox='0 0 690 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>
            <path d='M59.84,95L59.84,27.67Q53.79,26.69 50.08,26.69L50.08,26.69Q40.31,26.69 40.31,36.94L40.31,36.94L40.31,42.17L51.59,42.17L51.59,49.15L40.31,49.15L40.31,95L31.28,95L31.28,49.15L22.93,49.15L22.93,42.17L31.28,42.17L31.28,36.41Q31.33,27.96 36.02,23.47Q40.7,18.97 49.35,18.97L49.35,18.97Q54.28,18.97 68.88,21.95L68.88,21.95L68.88,95L59.84,95z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M116.44,95L116.24,89.78Q110.97,95.98 100.76,95.98L100.76,95.98Q92.31,95.98 87.9,91.07Q83.48,86.16 83.43,76.54L83.43,76.54L83.43,42.17L92.46,42.17L92.46,76.3Q92.46,88.31 102.23,88.31L102.23,88.31Q112.58,88.31 116,80.6L116,80.6L116,42.17L125.03,42.17L125.03,95L116.44,95z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M160.67,95.98L160.67,95.98Q149.93,95.98 143.19,88.92Q136.46,81.87 136.46,70.05L136.46,70.05L136.46,68.39Q136.46,60.53 139.46,54.35Q142.46,48.17 147.86,44.68Q153.25,41.19 159.55,41.19L159.55,41.19Q169.85,41.19 175.57,47.98Q181.28,54.77 181.28,67.41L181.28,67.41L181.28,71.17L145.49,71.17Q145.68,78.98 150.05,83.79Q154.42,88.6 161.16,88.6L161.16,88.6Q165.95,88.6 169.27,86.65Q172.59,84.7 175.08,81.47L175.08,81.47L180.6,85.77Q173.96,95.98 160.67,95.98z M159.55,48.61L159.55,48.61Q154.08,48.61 150.37,52.59Q146.66,56.57 145.78,63.75L145.78,63.75L172.25,63.75L172.25,63.07Q171.86,56.18 168.54,52.4Q165.21,48.61 159.55,48.61z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M191.73,42.17L200.27,42.17L200.57,48.81Q206.62,41.19 216.39,41.19L216.39,41.19Q233.13,41.19 233.28,60.09L233.28,60.09L233.28,95L224.25,95L224.25,60.04Q224.2,54.33 221.64,51.59Q219.07,48.86 213.65,48.86L213.65,48.86Q209.26,48.86 205.94,51.2Q202.62,53.54 200.76,57.35L200.76,57.35L200.76,95L191.73,95L191.73,42.17z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M250.13,29.38L259.16,29.38L259.16,42.17L269.02,42.17L269.02,49.15L259.16,49.15L259.16,81.91Q259.16,85.09 260.48,86.67Q261.8,88.26 264.97,88.26L264.97,88.26Q266.53,88.26 269.27,87.68L269.27,87.68L269.27,95Q265.7,95.98 262.33,95.98L262.33,95.98Q256.28,95.98 253.2,92.31Q250.13,88.65 250.13,81.91L250.13,81.91L250.13,49.15L240.51,49.15L240.51,42.17L250.13,42.17L250.13,29.38z ' fill='black' stroke='black' stroke-width='0' />
            <path d='' fill='black' stroke='black' stroke-width='0' />
            <path d='M301.93,68.73L301.93,68.1Q301.93,60.33 304.99,54.13Q308.04,47.93 313.48,44.56Q318.93,41.19 325.91,41.19L325.91,41.19Q336.7,41.19 343.36,48.66Q350.03,56.13 350.03,68.54L350.03,68.54L350.03,69.17Q350.03,76.88 347.08,83.01Q344.12,89.14 338.63,92.56Q333.13,95.98 326.01,95.98L326.01,95.98Q315.26,95.98 308.6,88.51Q301.93,81.04 301.93,68.73L301.93,68.73z M311.02,69.17L311.02,69.17Q311.02,77.96 315.09,83.28Q319.17,88.6 326.01,88.6L326.01,88.6Q332.89,88.6 336.94,83.21Q341,77.81 341,68.1L341,68.1Q341,59.4 336.87,54.01Q332.74,48.61 325.91,48.61L325.91,48.61Q319.22,48.61 315.12,53.94Q311.02,59.26 311.02,69.17z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M374.83,95L365.8,95L365.8,49.15L357.45,49.15L357.45,42.17L365.8,42.17L365.8,36.75Q365.8,28.25 370.34,23.61Q374.88,18.97 383.18,18.97L383.18,18.97Q386.31,18.97 389.38,19.8L389.38,19.8L388.9,27.13Q386.6,26.69 384.01,26.69L384.01,26.69Q379.62,26.69 377.23,29.25Q374.83,31.82 374.83,36.6L374.83,36.6L374.83,42.17L394.37,42.17L394.37,37.68Q394.37,28.84 399.42,23.91Q404.47,18.97 413.7,18.97L413.7,18.97Q419.17,18.97 427.52,21.95L427.52,21.95L426.01,29.57Q419.9,27.13 414.34,27.13L414.34,27.13Q408.53,27.13 405.96,29.72Q403.4,32.3 403.4,37.58L403.4,37.58L403.4,42.17L414.24,42.17L414.24,49.15L403.4,49.15L403.4,95L394.37,95L394.37,49.15L374.83,49.15L374.83,95z M431.96,42.17L431.96,95L422.93,95L422.93,42.17L431.96,42.17z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M467.9,88.6L467.9,88.6Q472.73,88.6 476.35,85.67Q479.96,82.74 480.35,78.35L480.35,78.35L488.9,78.35Q488.65,82.89 485.77,86.99Q482.89,91.09 478.08,93.54Q473.27,95.98 467.9,95.98L467.9,95.98Q457.11,95.98 450.74,88.77Q444.37,81.57 444.37,69.07L444.37,69.07L444.37,67.56Q444.37,59.84 447.2,53.84Q450.03,47.83 455.33,44.51Q460.62,41.19 467.85,41.19L467.85,41.19Q476.74,41.19 482.62,46.51Q488.51,51.84 488.9,60.33L488.9,60.33L480.35,60.33Q479.96,55.21 476.47,51.91Q472.98,48.61 467.85,48.61L467.85,48.61Q460.97,48.61 457.18,53.57Q453.4,58.53 453.4,67.9L453.4,67.9L453.4,69.61Q453.4,78.74 457.16,83.67Q460.92,88.6 467.9,88.6z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M520.98,95.98L520.98,95.98Q510.23,95.98 503.5,88.92Q496.76,81.87 496.76,70.05L496.76,70.05L496.76,68.39Q496.76,60.53 499.76,54.35Q502.76,48.17 508.16,44.68Q513.55,41.19 519.85,41.19L519.85,41.19Q530.16,41.19 535.87,47.98Q541.58,54.77 541.58,67.41L541.58,67.41L541.58,71.17L505.79,71.17Q505.99,78.98 510.36,83.79Q514.73,88.6 521.46,88.6L521.46,88.6Q526.25,88.6 529.57,86.65Q532.89,84.7 535.38,81.47L535.38,81.47L540.9,85.77Q534.26,95.98 520.98,95.98z M519.85,48.61L519.85,48.61Q514.38,48.61 510.67,52.59Q506.96,56.57 506.08,63.75L506.08,63.75L532.55,63.75L532.55,63.07Q532.16,56.18 528.84,52.4Q525.52,48.61 519.85,48.61z ' fill='black' stroke='black' stroke-width='0' />
            </svg>
            */
        }

        [TestMethod]
        public void CreateHorizontalGlyphOutlineIshindenshin()
        {
            string fontPath = System.IO.Path.Combine(Environment.CurrentDirectory, "NotoSerifJP-Regular.otf");
            Typeface tf;
            using (var fontStream = System.IO.File.OpenRead(fontPath))
            {
                // Initialize stream only
                tf = new Typeface(fontStream);
            }

            var svg = new System.Text.StringBuilder();
            double unit = 100;
            double x = 20;
            double y = 20;
            string japaneseText = "以心伝心";

            svg.AppendLine("<svg width='440' height='140' viewBox='0 0 440 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>");

            foreach (char c in japaneseText)
            {
                // Get glyph index
                ushort glyphIndex = tf.CharacterToGlyphMap[(int)c];

                // Get glyph outline
                var geometry = tf.GetGlyphOutline(glyphIndex, unit);

                // Get advanced width
                double advanceWidth = tf.AdvanceWidths[glyphIndex] * unit;

                // Get advanced height
                double advanceHeight = tf.AdvanceHeights[glyphIndex] * unit;

                // Get baseline
                double baseline = tf.Baseline * unit;

                // Convert to path mini-language
                string miniLanguage = geometry.Figures.ToString(x, y + baseline);

                svg.AppendLine($"<path d='{miniLanguage}' fill='black' stroke='black' stroke-width='0' />");
                x += advanceWidth;
            }

            svg.AppendLine("</svg>");
            System.Diagnostics.Trace.WriteLine(svg.ToString());
            /* Result
            <svg width='440' height='140' viewBox='0 0 440 140' xmlns='http://www.w3.org/2000/svg' version='1.1'>
            <path d='M57.1,41.2C63.2,46.9 71.4,56.2 73.9,63.3C81.8,68.4 86.2,52 58.1,40.4z M71.1,82.5C61.8,85.9 52.5,89.3 44.5,92.1L43.5,32.9C46.1,32.5 46.9,31.4 47,30L37,29.2L38,94.3C31.8,96.4 26.6,98.1 23.3,98.9L27.6,107.4C28.6,107 29.5,105.9 29.7,104.7C48,96.4 61.6,89.2 71.6,84z M98.5,29.4C97.6,67 93.2,93.3 46.9,113.8L48,115.7C68.8,108.2 81.9,99.3 90.3,88.9C97.8,96.3 106.5,106.4 109.6,114.2C117.9,119.5 121.7,102.5 91.9,86.8C102.7,72 104.6,54.3 105.6,33.6C107.8,33.3 109,32.2 109.3,30.7z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M136.5,57.2C136.7,70.6 131.1,82.5 125.2,87.1C123.4,89 122.5,91.5 123.9,93.3C125.6,95.3 129.6,94 132.5,90.9C136.9,86.2 142.4,74.8 138.3,57.2z M152.8,26.5L152.2,28.1C165.1,33.7 174,41.9 177.3,47.2C185.2,51.4 189.5,33.5 152.8,26.5z M195.6,56L194.6,57.1C205.5,66.4 209.1,81.1 209.4,90.2C216.7,98.7 225.3,72.3 195.6,56z M151,46.9L151,104.4C151,110.8 153.6,112.5 162.9,112.5L176.7,112.5C196.2,112.5 200,111.4 200,107.9C200,106.5 199.3,105.7 196.9,104.9L196.7,86.7L195.4,86.7C193.9,94.9 192.5,102.1 191.6,104.1C191.1,105.2 190.6,105.7 189.2,105.9C187.3,106.1 182.8,106.1 176.8,106.1L163.7,106.1C158.4,106.1 157.6,105.3 157.6,103L157.6,50.7C159.8,50.3 160.8,49.3 161,48z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M307.2,38.6C308.7,38.6 309.6,38.1 309.9,37.1C306.6,33.9 301.1,29.6 301.1,29.6L296.4,35.7L257.2,35.7L257.9,38.6z M246.5,24.2C241.4,43.2 232.7,62.2 224,74.3L225.4,75.3C229.8,71 234,65.8 237.9,59.9L237.9,115.7L239.1,115.7C241.5,115.7 244.3,114.1 244.4,113.5L244.4,54C246.2,53.7 247.1,53 247.4,52.1L243.4,50.6C247.1,44 250.3,36.8 253,29.3C255.2,29.4 256.4,28.6 256.9,27.5z M303.6,63.1L249,63.1L249.7,66.1L273.3,66.1C270.5,77.2 265.5,93.4 261.9,103C256.5,103.5 252,103.8 248.8,103.9L252.9,113C253.9,112.8 254.9,112.1 255.5,111C276.6,107 292,103.8 303.8,101.1C305.9,105.3 307.5,109.4 308.3,113C316.2,119.6 321.1,100.5 292,79.9L290.6,80.7C294.5,85.7 299.1,92.4 302.7,99.1C288.8,100.6 275.5,101.9 265,102.8C270.3,93.3 277.2,78 281.9,66.1L314.8,66.1C316,66.1 317,65.6 317.3,64.5C314,61.4 308.5,57.1 308.5,57.1z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M336.5,57.2C336.7,70.6 331.1,82.5 325.2,87.1C323.4,89 322.5,91.5 323.9,93.3C325.6,95.3 329.6,94 332.5,90.9C336.9,86.2 342.4,74.8 338.3,57.2z M352.8,26.5L352.2,28.1C365.1,33.7 374,41.9 377.3,47.2C385.2,51.4 389.5,33.5 352.8,26.5z M395.6,56L394.6,57.1C405.5,66.4 409.1,81.1 409.4,90.2C416.7,98.7 425.3,72.3 395.6,56z M351,46.9L351,104.4C351,110.8 353.6,112.5 362.9,112.5L376.7,112.5C396.2,112.5 400,111.4 400,107.9C400,106.5 399.3,105.7 396.9,104.9L396.7,86.7L395.4,86.7C393.9,94.9 392.5,102.1 391.6,104.1C391.1,105.2 390.6,105.7 389.2,105.9C387.3,106.1 382.8,106.1 376.8,106.1L363.7,106.1C358.4,106.1 357.6,105.3 357.6,103L357.6,50.7C359.8,50.3 360.8,49.3 361,48z ' fill='black' stroke='black' stroke-width='0' />
            </svg>
            */
        }

        [TestMethod]
        public void CreateVerticalGlyphOutlineFurinkazan()
        {
            string fontPath = System.IO.Path.Combine(Environment.CurrentDirectory, "NotoSansJP-Regular.otf");
            Typeface tf;
            using (var fontStream = System.IO.File.OpenRead(fontPath))
            {
                // Initialize stream only
                tf = new Typeface(fontStream);
            }

            // Get vertical glyph map
            var vertMap = tf.GetSingleSubstitutionMap("DFLT", "DFLT", "vert");

            var svg = new System.Text.StringBuilder();
            double unit = 100;
            double x = 20;
            double y = 20;
            string japaneseText = "【風林火山】";

            svg.AppendLine("<svg width='140' height='640' viewBox='0 0 140 640' xmlns='http://www.w3.org/2000/svg' version='1.1'>");

            foreach (char c in japaneseText)
            {
                // Get glyph index
                ushort glyphIndex = tf.CharacterToGlyphMap[(int)c];

                // Get vertical glyph index
                glyphIndex = vertMap.ContainsKey(glyphIndex) ? vertMap[glyphIndex] : glyphIndex;

                // Get glyph outline
                var geometry = tf.GetGlyphOutline(glyphIndex, unit);

                // Get advanced width
                double advanceWidth = tf.AdvanceWidths[glyphIndex] * unit;

                // Get advanced height
                double advanceHeight = tf.AdvanceHeights[glyphIndex] * unit;

                // Get baseline
                double baseline = tf.Baseline * unit;

                // Convert to path mini-language
                string miniLanguage = geometry.Figures.ToString(x, y + baseline);

                svg.AppendLine($"<path d='{miniLanguage}' fill='black' stroke='black' stroke-width='0' />");
                y += advanceHeight;
            }

            svg.AppendLine("</svg>");
            System.Diagnostics.Trace.WriteLine(svg.ToString());
            /* Result
            <svg width='140' height='640' viewBox='0 0 140 640' xmlns='http://www.w3.org/2000/svg' version='1.1'>
            <path d='M116.6,86.6L23.4,86.6L23.4,116.6L23.9,116.6C33.1,105.7 49.7,96.8 70,96.8C90.3,96.8 106.9,105.7 116.1,116.6L116.6,116.6z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M54.5,180.3L54.5,165.1L65.8,165.1L65.8,180.3z M83.8,165.1L83.8,180.3L72.4,180.3L72.4,165.1z M79.9,190.6C81.8,193.2 83.6,196.1 85.3,199.1L72.4,199.9L72.4,186.2L90.1,186.2L90.1,159.1L72.4,159.1L72.4,149.4C79.8,148.5 86.7,147.3 92.2,145.8L87,140.4C77.5,143 60.2,145 45.7,146C46.5,147.5 47.4,150 47.7,151.5C53.5,151.3 59.7,150.8 65.8,150.2L65.8,159.1L48.5,159.1L48.5,186.2L65.8,186.2L65.8,200.3C56.8,200.8 48.7,201.3 42.5,201.6L43,208.4C54.8,207.5 71.8,206.3 88.4,205.1C89.8,207.9 90.8,210.6 91.4,212.8L97.5,210.6C95.8,204.5 90.8,195.3 85.6,188.7z M35.7,129.8L35.7,161.8C35.7,177.1 34.6,197.4 23.9,211.6C25.6,212.5 28.6,214.5 29.8,215.8C41.1,200.7 42.8,178 42.8,161.8L42.8,136.6L96.8,136.6C97.1,180.2 97,215.6 109.2,215.6C114.3,215.6 115.8,210.6 116.5,197.7C115.1,196.5 113.2,194.4 111.9,192.4C111.7,201.1 111.2,207.9 109.9,207.9C104,207.9 103.8,166.9 103.9,129.8z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M67.2,273.3C64.8,270.4 54.2,258.2 50.9,255.1L50.9,252.8L65.1,252.8L65.1,245.7L50.9,245.7L50.9,224.3L43.6,224.3L43.6,245.7L25.8,245.7L25.8,252.8L42.3,252.8C38.5,266.6 30.8,282 23.3,290.4C24.6,292.2 26.4,295.1 27.3,297.3C33.3,290.3 39.3,278.7 43.6,266.7L43.6,315.5L50.9,315.5L50.9,264C55,269.2 60.1,276.1 62.3,279.7z M113.6,252.8L113.6,245.7L94.7,245.7L94.7,224.3L87.4,224.3L87.4,245.7L69.4,245.7L69.4,252.8L85.8,252.8C81.2,268.8 71.9,285.1 62.4,294.4C63.8,296.1 65.8,298.9 66.8,300.9C74.6,293.1 82.1,280.1 87.4,266.4L87.4,315.5L94.7,315.5L94.7,266.1C99.1,279.2 104.9,291.4 111,299.1C112.3,297.1 114.9,294.6 116.7,293.3C108.7,284.6 101.1,268.6 96.6,252.8z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M73.5,325.8L65.6,325.8L65.6,357.9C65.6,369.5 58.7,396.8 25.2,409.6C26.9,411.1 29.3,414.2 30.3,415.7C58.5,404.1 67.6,382 69.5,372.3C71.5,381.9 81.2,404.8 110.1,415.7C111.2,413.7 113.4,410.5 115,408.9C80.6,396.7 73.5,369.3 73.5,357.9z M102.7,344.3C99.4,353 93.1,365 88.2,372.3L94.4,375.2C99.5,368.1 105.9,356.8 110.7,347.5z M40.4,344.5C38.8,355.6 35.4,366.4 27.4,372.4L33.8,376.8C42.7,370 46,357.9 47.8,346z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M101.9,447.9L101.9,498.8L73.4,498.8L73.4,426.4L65.8,426.4L65.8,498.8L38.3,498.8L38.3,448L30.8,448L30.8,514.4L38.3,514.4L38.3,506.3L101.9,506.3L101.9,514L109.5,514L109.5,447.9z ' fill='black' stroke='black' stroke-width='0' />
            <path d='M116.6,553.4L116.6,523.4L116.1,523.4C106.9,534.3 90.3,543.2 70,543.2C49.7,543.2 33.1,534.3 23.9,523.4L23.4,523.4L23.4,553.4z ' fill='black' stroke='black' stroke-width='0' />
            </svg>
            */
        }
    }
}
